/*--------------------------------------------------------------------
 * guc.h
 *
 * 与backend/utils/misc/guc.c和backend/utils/misc/guc-file.l相关的外部声明
 *
 * Copyright (c) 2000-2022, PostgreSQL Global Development Group
 * Written by Peter Eisentraut <peter_e@gmx.net>.
 *
 * src/include/utils/guc.h
 *--------------------------------------------------------------------
 */
#ifndef GUC_H
#define GUC_H

#include "nodes/parsenodes.h"
#include "tcop/dest.h"
#include "utils/array.h"


/* 以千字节为单位测量的 GUC 变量的上限 */
/* 注意各种地方假设字节大小适合“长”变量 */
#if SIZEOF_SIZE_T > 4 && SIZEOF_LONG > 4
#define MAX_KILOBYTES	INT_MAX
#else
#define MAX_KILOBYTES	(INT_MAX / 1024)
#endif

/*
 * ALTER SYSTEM 的自动配置文件名。
 * 此文件将用于存储由 ALTER SYSTEM 命令设置的配置参数值。
 */
#define PG_AUTOCONF_FILENAME		"postgresql.auto.conf"

/*
 * 某些选项只能在特定的时间设置。规则如下：
 *
 * INTERNAL 选项根本不能由用户设置，只能通过内部过程设置（“server_version”就是一个例子）。这些仅是 GUC 变量，因此它们可以通过 SHOW 等命令显示。
 *
 * POSTMASTER 选项只能在 postmaster 启动时设置，可以通过配置文件或命令行提供。
 *
 * SIGHUP 选项只能在 postmaster 启动时设置，或通过更改配置文件并向 postmaster 或后端进程发送 HUP 信号来设置。（注意，信号接收不会立即评估。postmaster 和后端在其主循环的某个时刻检查它。等待而不是异步读取文件更安全。）
 *
 * BACKEND 和 SU_BACKEND 选项只能在 postmaster 启动时从配置文件设置，或通过客户端在连接启动数据包中请求（例如来自 libpq 的 PGOPTIONS 变量）。SU_BACKEND 选项只能在用户为超级用户时从启动数据包设置。此外，已经启动的后端将忽略对配置文件中此类选项的更改。其想法是这些选项在给定后端启动后是固定的，但它们可以在不同的后端之间有所不同。
 *
 * SUSET 选项可以在 postmaster 启动时设置，可以通过 SIGHUP 机制设置，或在，你是超级用户时通过启动数据包或 SQL 设置。
 *
 * USERSET 选项可以由任何人随时设置。
 */
typedef enum
{
	PGC_INTERNAL,
	PGC_POSTMASTER,
	PGC_SIGHUP,
	PGC_SU_BACKEND,
	PGC_BACKEND,
	PGC_SUSET,
	PGC_USERSET
} GucContext;

/*
 * 以下类型记录当前设置的来源。只有在先前的设置具有相同或更低级别时，新设置才能生效。（例如，修改配置文件不会覆盖 postmaster 命令行。）跟踪源允许我们以任何方便的顺序处理源而不影响结果。
 * 源 <= PGC_S_OVERRIDE 将设置 RESET 使用的默认值，以及当前值。
 *
 * PGC_S_INTERACTIVE 实际上并不是源值，而是用于错误报告目的的“交互式”和“非交互式”源之间的分界线。
 *
 * PGC_S_TEST 用于测试稍后要使用的值。例如，ALTER DATABASE/ROLE 以这种方式测试提议的每个数据库或每个用户的默认值，而 CREATE FUNCTION 以这种方式测试提议的函数 SET 子句。这是一个交互式案例，但它需要自己的源值，因为某些赋值钩子需要在这种情况下进行不同的有效性检查。特别是，对不存在的数据库对象的引用通常不应该在此情况下抛出硬错误，最多只发出 NOTICE，因为这些对象在设置实际使用时可能存在。
 *
 * 当设置非编译时常量 PGC_INTERNAL 选项的值时，通常应该使用 source == PGC_S_DYNAMIC_DEFAULT，以便该值将在 pg_settings 中显示为“默认”。如果有特定原因不想这样，使用 source == PGC_S_OVERRIDE。
 *
 * 注意：如果更改此内容，请参见 guc.c 中的 GucSource_Names。
 */
typedef enum
{
	PGC_S_DEFAULT,				/* 硬编码的默认值（"boot_val"） */
	PGC_S_DYNAMIC_DEFAULT,		/* 在初始化期间计算的默认值 */
	PGC_S_ENV_VAR,				/* postmaster 环境变量 */
	PGC_S_FILE,					/* postgresql.conf */
	PGC_S_ARGV,					/* postmaster 命令行 */
	PGC_S_GLOBAL,				/* 全局数据库内设置 */
	PGC_S_DATABASE,				/* 每个数据库设置 */
	PGC_S_USER,					/* 每个用户设置 */
	PGC_S_DATABASE_USER,		/* 每个用户和数据库设置 */
	PGC_S_CLIENT,				/* 来自客户端连接请求 */
	PGC_S_OVERRIDE,				/* 强制设置默认值的特殊情况 */
	PGC_S_INTERACTIVE,			/* 错误报告的分界线 */
	PGC_S_TEST,					/* 测试每个数据库或每个用户的设置 */
	PGC_S_SESSION				/* SET 命令 */
} GucSource;

/*
 * 解析配置文件将返回一个名称-值对的列表，并带有源位置信息。我们还滥用这个数据结构来携带有关配置文件的错误报告。报告错误的条目将有 errmsg != NULL，并且可能在名称、值和/或文件名上有 NULL。
 *
 * 如果“ignore”为真，则不尝试应用该项（它可能是错误报告，或者是我们确定为重复的项）。如果我们成功应用或可能应用设置，则“applied”被设置为真。
 */
typedef struct ConfigVariable
{
	char	   *name;
	char	   *value;
	char	   *errmsg;
	char	   *filename;
	int			sourceline;
	bool		ignore;
	bool		applied;
	struct ConfigVariable *next;
} ConfigVariable;

extern bool ParseConfigFile(const char *config_file, bool strict,
							const char *calling_file, int calling_lineno,
							int depth, int elevel,
							ConfigVariable **head_p, ConfigVariable **tail_p);
extern bool ParseConfigFp(FILE *fp, const char *config_file,
						  int depth, int elevel,
						  ConfigVariable **head_p, ConfigVariable **tail_p);
extern bool ParseConfigDirectory(const char *includedir,
								 const char *calling_file, int calling_lineno,
								 int depth, int elevel,
								 ConfigVariable **head_p,
								 ConfigVariable **tail_p);
extern void FreeConfigVariables(ConfigVariable *list);
extern char *DeescapeQuotedString(const char *s);

/*
 * 枚举变量的可能值由名称-值对数组指定。“hidden”标志意味着值被接受，但在请求 guc.c 的可接受值列表时不会显示。
 */
struct config_enum_entry
{
	const char *name;
	int			val;
	bool		hidden;
};

/*
 * 每个变量检查/赋值/显示钩子函数的签名
 */
typedef bool (*GucBoolCheckHook) (bool *newval, void **extra, GucSource source);
typedef bool (*GucIntCheckHook) (int *newval, void **extra, GucSource source);
typedef bool (*GucRealCheckHook) (double *newval, void **extra, GucSource source);
typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource source);
typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source);

typedef void (*GucBoolAssignHook) (bool newval, void *extra);
typedef void (*GucIntAssignHook) (int newval, void *extra);
typedef void (*GucRealAssignHook) (double newval, void *extra);
typedef void (*GucStringAssignHook) (const char *newval, void *extra);
typedef void (*GucEnumAssignHook) (int newval, void *extra);

typedef const char *(*GucShowHook) (void);


/*
 * 杂项
 */
typedef enum
{
	/* set_config_option 操作类型 */
	GUC_ACTION_SET,				/* 常规 SET 命令 */
	GUC_ACTION_LOCAL,			/* SET LOCAL 命令 */
	GUC_ACTION_SAVE				/* 函数设置选项或临时赋值 */
} GucAction;

#define GUC_QUALIFIER_SEPARATOR '.'

/*
 * GUC变量"flags"中的位值
 */
#define GUC_LIST_INPUT			0x0001	/* 输入可以是列表格式 */
#define GUC_LIST_QUOTE			0x0002	/* 双引号列表元素 */
#define GUC_NO_SHOW_ALL			0x0004	/* 从SHOW ALL排除 */
#define GUC_NO_RESET_ALL		0x0008	/* 从RESET ALL排除 */
#define GUC_REPORT				0x0010	/* 自动报告对客户端的更改 */
#define GUC_NOT_IN_SAMPLE		0x0020	/* 不在postgresql.conf.sample中 */
#define GUC_DISALLOW_IN_FILE	0x0040	/* 不能在postgresql.conf中设置 */
#define GUC_CUSTOM_PLACEHOLDER	0x0080	/* 自定义变量的占位符 */
#define GUC_SUPERUSER_ONLY		0x0100	/* 仅对超级用户可见 */
#define GUC_IS_NAME				0x0200	/* 字符串长度限制为NAMEDATALEN-1 */
#define GUC_NOT_WHILE_SEC_REST	0x0400	/* 如果安全受到限制，则无法设置 */
#define GUC_DISALLOW_IN_AUTO_FILE 0x0800	/* 不能在
											 * PG_AUTOCONF_FILENAME中设置 */

#define GUC_UNIT_KB				0x1000	/* 值以千字节为单位 */
#define GUC_UNIT_BLOCKS			0x2000	/* 值的单位是块 */
#define GUC_UNIT_XBLOCKS		0x3000	/* 值的单位是 xlog 块 */
#define GUC_UNIT_MB				0x4000	/* 值以兆字节为单位 */
#define GUC_UNIT_BYTE			0x8000	/* 值以字节为单位 */
#define GUC_UNIT_MEMORY			0xF000	/* 与大小相关的单位掩码 */

#define GUC_UNIT_MS			   0x10000	/* 值以毫秒为单位 */
#define GUC_UNIT_S			   0x20000	/* 值以秒为单位 */
#define GUC_UNIT_MIN		   0x30000	/* 值以分钟为单位 */
#define GUC_UNIT_TIME		   0xF0000	/* 与时间相关的单位的掩码 */

#define GUC_EXPLAIN			  0x100000	/* 在解释中包含 */

/*
 * GUC_RUNTIME_COMPUTED 是针对仅在服务器未运行时通过 'postgres -C' 可用的运行时计算 GUC 的设计。
 */
#define GUC_RUNTIME_COMPUTED  0x200000
#define GUC_ALLOW_IN_PARALLEL 0x400000	/* 允许在并行模式下设置 */

#define GUC_UNIT				(GUC_UNIT_MEMORY | GUC_UNIT_TIME)


/* 实际上在guc.c中声明的GUC变量，而不是在其他地方 */
extern PGDLLIMPORT bool Debug_print_plan;
extern PGDLLIMPORT bool Debug_print_parse;
extern PGDLLIMPORT bool Debug_print_rewritten;
extern PGDLLIMPORT bool Debug_pretty_print;

extern PGDLLIMPORT bool log_parser_stats;
extern PGDLLIMPORT bool log_planner_stats;
extern PGDLLIMPORT bool log_executor_stats;
extern PGDLLIMPORT bool log_statement_stats;
extern PGDLLIMPORT bool log_btree_build_stats;

extern PGDLLIMPORT bool check_function_bodies;
extern PGDLLIMPORT bool session_auth_is_superuser;

extern PGDLLIMPORT bool log_duration;
extern PGDLLIMPORT int log_parameter_max_length;
extern PGDLLIMPORT int log_parameter_max_length_on_error;
extern PGDLLIMPORT int log_min_error_statement;
extern PGDLLIMPORT int log_min_messages;
extern PGDLLIMPORT int client_min_messages;
extern PGDLLIMPORT int log_min_duration_sample;
extern PGDLLIMPORT int log_min_duration_statement;
extern PGDLLIMPORT int log_temp_files;
extern PGDLLIMPORT double log_statement_sample_rate;
extern PGDLLIMPORT double log_xact_sample_rate;
extern PGDLLIMPORT char *backtrace_functions;
extern PGDLLIMPORT char *backtrace_symbol_list;

extern PGDLLIMPORT int temp_file_limit;

extern PGDLLIMPORT int num_temp_buffers;

extern PGDLLIMPORT char *cluster_name;
extern PGDLLIMPORT char *ConfigFileName;
extern PGDLLIMPORT char *HbaFileName;
extern PGDLLIMPORT char *IdentFileName;
extern PGDLLIMPORT char *external_pid_file;

extern PGDLLIMPORT char *application_name;

extern PGDLLIMPORT int tcp_keepalives_idle;
extern PGDLLIMPORT int tcp_keepalives_interval;
extern PGDLLIMPORT int tcp_keepalives_count;
extern PGDLLIMPORT int tcp_user_timeout;

#ifdef TRACE_SORT
extern PGDLLIMPORT bool trace_sort;
#endif

/*
 * guc.c导出的函数
 */
extern void SetConfigOption(const char *name, const char *value,
							GucContext context, GucSource source);

extern void DefineCustomBoolVariable(const char *name,
									 const char *short_desc,
									 const char *long_desc,
									 bool *valueAddr,
									 bool bootValue,
									 GucContext context,
									 int flags,
									 GucBoolCheckHook check_hook,
									 GucBoolAssignHook assign_hook,
									 GucShowHook show_hook);

extern void DefineCustomIntVariable(const char *name,
									const char *short_desc,
									const char *long_desc,
									int *valueAddr,
									int bootValue,
									int minValue,
									int maxValue,
									GucContext context,
									int flags,
									GucIntCheckHook check_hook,
									GucIntAssignHook assign_hook,
									GucShowHook show_hook);

extern void DefineCustomRealVariable(const char *name,
									 const char *short_desc,
									 const char *long_desc,
									 double *valueAddr,
									 double bootValue,
									 double minValue,
									 double maxValue,
									 GucContext context,
									 int flags,
									 GucRealCheckHook check_hook,
									 GucRealAssignHook assign_hook,
									 GucShowHook show_hook);

extern void DefineCustomStringVariable(const char *name,
									   const char *short_desc,
									   const char *long_desc,
									   char **valueAddr,
									   const char *bootValue,
									   GucContext context,
									   int flags,
									   GucStringCheckHook check_hook,
									   GucStringAssignHook assign_hook,
									   GucShowHook show_hook);

extern void DefineCustomEnumVariable(const char *name,
									 const char *short_desc,
									 const char *long_desc,
									 int *valueAddr,
									 int bootValue,
									 const struct config_enum_entry *options,
									 GucContext context,
									 int flags,
									 GucEnumCheckHook check_hook,
									 GucEnumAssignHook assign_hook,
									 GucShowHook show_hook);

extern void MarkGUCPrefixReserved(const char *className);

/* MarkGUCPrefixReserved的旧名称，兼容性考虑: */
#define EmitWarningsOnPlaceholders(className) MarkGUCPrefixReserved(className)

extern const char *GetConfigOption(const char *name, bool missing_ok,
								   bool restrict_privileged);
extern const char *GetConfigOptionResetString(const char *name);
extern int	GetConfigOptionFlags(const char *name, bool missing_ok);
extern void ProcessConfigFile(GucContext context);
extern char *convert_GUC_name_for_parameter_acl(const char *name);
extern bool check_GUC_name_for_parameter_acl(const char *name);
extern void InitializeGUCOptions(void);
extern void InitializeWalConsistencyChecking(void);
extern bool SelectConfigFiles(const char *userDoption, const char *progname);
extern void ResetAllOptions(void);
extern void AtStart_GUC(void);
extern int	NewGUCNestLevel(void);
extern void AtEOXact_GUC(bool isCommit, int nestLevel);
extern void BeginReportingGUCOptions(void);
extern void ReportChangedGUCOptions(void);
extern void ParseLongOption(const char *string, char **name, char **value);
extern bool parse_int(const char *value, int *result, int flags,
					  const char **hintmsg);
extern bool parse_real(const char *value, double *result, int flags,
					   const char **hintmsg);
extern int	set_config_option(const char *name, const char *value,
							  GucContext context, GucSource source,
							  GucAction action, bool changeVal, int elevel,
							  bool is_reload);
extern int	set_config_option_ext(const char *name, const char *value,
								  GucContext context, GucSource source,
								  Oid srole,
								  GucAction action, bool changeVal, int elevel,
								  bool is_reload);
extern void AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt);
#ifdef FDD
//用于限制三权分立下，只有对应的用户才能够修改其权限范围内的系统配置项 
extern void FDB_AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt, bool isSso);
#endif
extern char *GetConfigOptionByName(const char *name, const char **varname,
								   bool missing_ok);
extern void GetConfigOptionByNum(int varnum, const char **values, bool *noshow);
extern int	GetNumConfigOptions(void);

extern void SetPGVariable(const char *name, List *args, bool is_local);
extern void GetPGVariable(const char *name, DestReceiver *dest);
extern TupleDesc GetPGVariableResultDesc(const char *name);

extern void ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel);
extern char *ExtractSetVariableArgs(VariableSetStmt *stmt);

extern void ProcessGUCArray(ArrayType *array,
							GucContext context, GucSource source, GucAction action);
extern ArrayType *GUCArrayAdd(ArrayType *array, const char *name, const char *value);
extern ArrayType *GUCArrayDelete(ArrayType *array, const char *name);
extern ArrayType *GUCArrayReset(ArrayType *array);

#ifdef EXEC_BACKEND
extern void write_nondefault_variables(GucContext context);
extern void read_nondefault_variables(void);
#endif

/* GUC序列化 */
extern Size EstimateGUCStateSpace(void);
extern void SerializeGUCState(Size maxsize, char *start_address);
extern void RestoreGUCState(void *gucstate);

/* 支持从GUC检查钩子报告的消息 */

extern PGDLLIMPORT char *GUC_check_errmsg_string;
extern PGDLLIMPORT char *GUC_check_errdetail_string;
extern PGDLLIMPORT char *GUC_check_errhint_string;

extern void GUC_check_errcode(int sqlerrcode);

#define GUC_check_errmsg \
	pre_format_elog_string(errno, TEXTDOMAIN), \
	GUC_check_errmsg_string = format_elog_string

#define GUC_check_errdetail \
	pre_format_elog_string(errno, TEXTDOMAIN), \
	GUC_check_errdetail_string = format_elog_string

#define GUC_check_errhint \
	pre_format_elog_string(errno, TEXTDOMAIN), \
	GUC_check_errhint_string = format_elog_string


/*
 * 以下函数不在guc.c中，但在此声明以避免
 * 在一些广泛使用的标题中包含guc.h，实际上它并不适合。
 */

/* 在commands/tablespace.c中 */
extern bool check_default_tablespace(char **newval, void **extra, GucSource source);
extern bool check_temp_tablespaces(char **newval, void **extra, GucSource source);
extern void assign_temp_tablespaces(const char *newval, void *extra);

/* 在catalog/namespace.c中 */
extern bool check_search_path(char **newval, void **extra, GucSource source);
extern void assign_search_path(const char *newval, void *extra);

/* 在access/transam/xlog.c中 */
extern bool check_wal_buffers(int *newval, void **extra, GucSource source);
extern void assign_xlog_sync_method(int new_sync_method, void *extra);

/* 在access/transam/xlogprefetcher.c中 */
extern bool check_recovery_prefetch(int *new_value, void **extra, GucSource source);
extern void assign_recovery_prefetch(int new_value, void *extra);

#endif							/* GUC_H */
